﻿using MX.Core.Caching;
using MX.Core.Caching.Memcached;
using MX.Core.Caching.Redis;
using MX.Core.Extensions; 
using MX.Core.Log; 
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MX.Core.Http.Session
{
	/// <summary>
	/// 负责会话ID和最后访问时间的维护
	/// </summary>
	abstract public class SessionManager<T>
	{
		const string CACHENAME = "MX.HTTP.SESSION";

		[Serializable ()]
		public class OnlinePassport
		{
			public string SessionKey { get; set; }

			public string MemberId { get; set; }

			/// <summary>
			/// 登录IP
			/// </summary>
			public string LoginIP {
				get;
				set;
			}

			/// <summary>
			/// 登录时间
			/// </summary>
			public DateTime LoginDateTime {
				get;
				set;
			}

			/// <summary>
			/// 附加参数
			/// </summary>
			public T Parameter { get; set; }
		}

		/// <summary>
		/// 会话超时时间（分钟单位）
		/// </summary>
		virtual public int SessionTimeout { get { return 5; } }

		public virtual string CacheConfigName {
			get { return "MX.Core.Session"; }
		}

		/// <summary>
		/// 会话IDcookie名称
		/// </summary>
		public virtual string TOKENNAME {
			get {
				return "_T";
			}
		}

		/// <summary>
		/// 最后写入时间cookie名称
		/// </summary>
		public virtual string LASTWRITE {
			get {
				return "_LW";
			}
		}



		/// <summary>
		/// 最大写入间隔时间（秒）
		/// </summary>
		public virtual int MaxWriteTime {
			get {

				return 30;
			}
		}

		/// <summary>
		/// 用户会话ID缓存存储KEY
		/// </summary>
		public virtual string UserIdKey { get { return "_UID"; } }

		/// <summary>
		/// 用户会话信息缓存存储KEY
		/// </summary>
		public virtual string UserInfoKey { get { return "_USERINFO"; } }

		/// <summary>
		/// 用户会话信息缓存存储KEY
		/// </summary>
		public virtual string LogName { get { return " 在线状态管理"; } }

		/// <summary>
		/// 缓存对象
		/// </summary>
		RedisCaching sessionCached;
		/// <summary>
		/// 日志对象
		/// </summary>
		ILogger log;

		public SessionManager ()
		{
			sessionCached = new RedisCachingFactory ().CreateRedisCaching (CacheConfigName);
			log = Logger.GetLogger ("在线状态管理");
		}

		/// <summary>
		/// 生成会话ID
		/// </summary>
		/// <returns></returns>
		private string GetSid ()
		{
			return Guid.NewGuid ().ToString ().MD5 ().Substring (8, 16);
		}

		/// <summary>
		/// 获取会话ID
		/// </summary>
		/// <returns></returns>
		public string GetSessionId ()
		{
			string token = GetCookie (TOKENNAME);
			if (string.IsNullOrEmpty (token)) {
				token = GetSid ();
				SetCookie (TOKENNAME, token);
			}
			return token;
		}

		private void SetCookie (string name, string value)
		{
			//WebContext.Cookies.PutValue (name, value);
		}

		/// <summary>
		/// 设置会话ID
		/// </summary>
		public void SetSessionId ()
		{
			//var request = HttpContext.Current.Request;
			string token = GetSessionId ();
			bool needWrite = true;
			string lastWriteTimeStr = GetCookie (LASTWRITE);
			long now = DateTime.Now.ToTimestamp ();
			if (!string.IsNullOrEmpty (token)) {
				if (lastWriteTimeStr.IsInteger ()) {
					if ((now - lastWriteTimeStr.As<long> ()) < MaxWriteTime * 1000) {
						needWrite = false;
					}
				}
			}
			if (needWrite) {
				SetLastWrite (token, now);
			}
		}

		private string GetCookie (string name)
		{
            throw new Exception("待重新实现");
			///return WebContext.Cookies.GetValue (name);
		}

		/// <summary>
		/// 设置当前会话的存储对象
		/// </summary>
		/// <param name="key"></param>
		/// <param name="value"></param>
		public void SetSessionObject (string key, object value)
		{
			string sessionKey = GetSessionId ();
			SetCache (sessionKey + key, value);
		}


		/// <summary>
		/// 获取当前会话的存储对象
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="key"></param>
		/// <returns></returns>
		public F GetSessionObject<F> (string key)
		{
			string sessionKey = GetSessionId ();
			return GetCache<F> (sessionKey + key);
		}


		/// <summary>
		/// 设置最后访问时间
		/// </summary>
		/// <param name="sessionId"></param>
		/// <param name="timestamp"></param>
		public void SetLastWrite (string sessionId, long timestamp)
		{
			SetCache (sessionId + LASTWRITE, timestamp);
			SetCookie (LASTWRITE, timestamp.ToString ());
		}

		/// <summary>
		/// 删除会话对象
		/// </summary>
		/// <param name="USERID"></param>
		public void DeleteSessionObject (string key)
		{
			string sessionKey = GetSessionId ();
			DeleteCache (sessionKey + key);
		}


		private void DeleteCache (string key)
		{
			sessionCached.Remove (key);
		}

		private F GetCache<F> (string key)
		{
			return sessionCached.Get<F> (key);
		}

		private void SetCache (string key, object value)
		{
			sessionCached.Set (key, value,DateTime.Now.AddDays(1));
		}

		public bool Login (T pars, out string msg)
        {
            throw new Exception("待重新实现");
   //         msg = "";
			//try {

			//	string memberId;
			//	if (CheckPassport (pars, out memberId, out msg) && !string.IsNullOrEmpty (memberId)) {
			//		var passport = new OnlinePassport ();
			//		string sessionKey = GetSessionId ();
			//		passport.SessionKey = sessionKey;
			//		passport.LoginDateTime = DateTime.Now;
			//		passport.LoginIP = WebContext.Request.RemoteAddress;
			//		passport.MemberId = memberId;
			//		Logout (sessionKey);
			//		SetInfo (passport); 
			//		sessionCached.HSet (CACHENAME, sessionKey, passport);
			//		return true;
			//	}
			//} catch (Exception ex) {
			//	msg = "执行错误";
			//	log.Error (ex, "登录异常");
			//}
			//return false;
		}


		/// <summary>
		/// 设置缓存信息
		/// </summary>
		/// <param name="info"></param>
		private void SetInfo (OnlinePassport passport)
		{
			if (passport == null)
				return;
			SetSessionObject (UserIdKey, passport.MemberId);
			SetSessionObject (UserInfoKey, passport);
			SetLastWrite (GetSessionId (), DateTime.Now.ToTimestamp ());
		}

		/// <summary>
		/// 注销用户
		/// </summary>
		/// <param name="sessionKey"></param>
		public void Logout (string sessionKey)
		{
			try {
				string userIdKey = sessionKey + UserIdKey;
				string userInfoKey = sessionKey + UserInfoKey;
				DeleteCache (userIdKey);
				DeleteCache (userInfoKey); 
				if (!sessionCached.HDel (CACHENAME, sessionKey)) {
					log.Error ("注销失败sessionKey:" + sessionKey);
				}
			} catch (Exception ex) {
				log.Error (ex, "注销错误sessionKey:" + sessionKey);
			}
		}


		/// <summary>
		/// 注销设备在线状态
		/// </summary>
		/// <param name="sessionKeys"></param>
		/// <returns></returns>
		public void Logout (IEnumerable<string> sessionKeys)
		{
			try {
				if (sessionKeys.Any ()) {
					foreach (var sessionKey in sessionKeys) {
						string userIdKey = sessionKey + UserIdKey;
						string userInfoKey = sessionKey + UserInfoKey;
						DeleteCache (userIdKey);
						DeleteCache (userInfoKey);
					}

				}
			} catch (Exception ex) {
				log.Error (ex, "注销错误sessionKey:" + string.Join (",", sessionKeys));
			}

		}


		/// <summary>
		/// 是否登录
		/// </summary>
		/// <returns></returns>
		public bool IsLogin ()
		{
			return !string.IsNullOrEmpty (GetUserId ());
		}

		/// <summary>
		/// 获取用户ID
		/// </summary>
		/// <returns></returns>
		public string GetUserId ()
		{
			return GetSessionObject<string> (UserIdKey);
		}

		/// <summary>
		/// 获取会员基础信息
		/// </summary>
		/// <returns></returns>
		public OnlinePassport GetUserInfo ()
		{
			return GetSessionObject<OnlinePassport> (UserInfoKey);
		}

		/// <summary>
		/// 后台超时注销用户
		/// </summary>
		public List<OnlinePassport> ClearSession ()
		{
			try {
				var list =	sessionCached.HVals<OnlinePassport> (CACHENAME);
				list = list.Where (p => p.LoginDateTime.AddMinutes (SessionTimeout) < DateTime.Now).ToList ();
				List<OnlinePassport> logoutList = new List<OnlinePassport> ();

				foreach (var online in list) {
					var sessionKey = online.SessionKey;
					var memberID = online.MemberId;
					string lastWriteKey = sessionKey + LASTWRITE;
					var lastWriteTime = GetCache<long> (lastWriteKey);
					long now = DateTime.Now.ToTimestamp ();
					if (now - lastWriteTime > SessionTimeout * 60) {
						logoutList.Add (online);
					}
				}
				if (logoutList.Count > 0) {
					Logout (logoutList.Select (p => p.SessionKey));
				}
				return logoutList;
			} catch (Exception ex) {
				log.Error (ex, "会话清理错误：" + ex.Message);
			}
			return null;
		}


		abstract public bool CheckPassport (T pars, out string memberId, out string msg);


		public void Logout ()
		{
			Logout (GetSessionId ());
		}
	}
}
